Stack
A comprehensive guide to stack algorithms and techniques for Data Structures and Algorithms.
Table of Contents
- Introduction to Stacks
- Basic Stack Operations
- Stack Implementation
- Basic Stack Problems
- Expression Evaluation
- Parentheses Problems
- Monotonic Stack
- Stack in Recursion
- Two Stacks Problems
- Stack with Additional Operations
- Advanced Stack Patterns
- Stack in Graph Algorithms
- Memory Management
- Common Optimization Tricks
Introduction to Stacks
A Stack is a linear data structure that follows the Last In First Out (LIFO) principle. Elements are added and removed from the same end, called the "top" of the stack.
Core Concepts
LIFO Principle: The last element pushed onto the stack is the first one to be popped off.
Main Operations:
- Push: Add an element to the top
- Pop: Remove the top element
- Peek/Top: View the top element without removing it
- isEmpty: Check if stack is empty
Basic Template
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) return null;
return this.items.pop();
}
peek() {
if (this.isEmpty()) return null;
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
}
Basic Stack Operations
1. Stack Using Array
class ArrayStack {
constructor(maxSize = 1000) {
this.items = new Array(maxSize);
this.top = -1;
this.maxSize = maxSize;
}
push(element) {
if (this.isFull()) {
throw new Error("Stack Overflow");
}
this.items[++this.top] = element;
}
pop() {
if (this.isEmpty()) {
throw new Error("Stack Underflow");
}
return this.items[this.top--];
}
peek() {
if (this.isEmpty()) return null;
return this.items[this.top];
}
isEmpty() {
return this.top === -1;
}
isFull() {
return this.top === this.maxSize - 1;
}
size() {
return this.top + 1;
}
}
2. Stack Using Linked List
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class LinkedListStack {
constructor() {
this.head = null;
this.stackSize = 0;
}
push(element) {
const newNode = new Node(element);
newNode.next = this.head;
this.head = newNode;
this.stackSize++;
}
pop() {
if (this.isEmpty()) return null;
const poppedData = this.head.data;
this.head = this.head.next;
this.stackSize--;
return poppedData;
}
peek() {
return this.isEmpty() ? null : this.head.data;
}
isEmpty() {
return this.head === null;
}
size() {
return this.stackSize;
}
}
Basic Stack Problems
1. Reverse a String
function reverseString(str) {
const stack = new Stack();
// Push all characters
for (const char of str) {
stack.push(char);
}
// Pop all characters
let reversed = "";
while (!stack.isEmpty()) {
reversed += stack.pop();
}
return reversed;
}
2. Check Palindrome
function isPalindrome(str) {
const stack = new Stack();
const n = str.length;
// Push first half
for (let i = 0; i < Math.floor(n / 2); i++) {
stack.push(str[i]);
}
// Compare second half with stack
let start = n % 2 === 0 ? Math.floor(n / 2) : Math.floor(n / 2) + 1;
for (let i = start; i < n; i++) {
if (stack.pop() !== str[i]) {
return false;
}
}
return true;
}
3. Next Greater Element
function nextGreaterElement(arr) {
const result = new Array(arr.length).fill(-1);
const stack = new Stack();
for (let i = 0; i < arr.length; i++) {
while (!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
const index = stack.pop();
result[index] = arr[i];
}
stack.push(i);
}
return result;
}